﻿using System;
using System.Diagnostics.Contracts;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Drawing;
using System.Net.Http;
using System.Web;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using WxLib.Core.Util;
using WxLib.Core.Serializers;
using WxLib.Core.RequestHandlers;
using WxLib.Common;
using WxLib.QRCode;

namespace WxLib.QRCode
{
    /// <summary>
    /// 微信小程序二维码
    /// </summary>
    public class WxAppQRCode  
    {
        private string defaultUri = "https://api.weixin.qq.com";
        private readonly WxApiOptions options;

        /// <summary>
        /// 构造函数
        /// </summary>
        public WxAppQRCode(IOptions<WxApiOptions> optionsAccessor)
        {
            Method = HttpMethod.Post;
            BaseUri = new Uri(defaultUri);
            RequestHandler = new RequestHandler(new JsonSerializer());
            ImageRequestHandler = new ImageRequestHandler();
            this.options = optionsAccessor.Value;
        }

        /// <summary>
        /// 获取或设置HTTP请求协议
        /// </summary>
        public HttpMethod Method { get; set; }

        /// <summary>
        /// 获取或设置用于执行请求的RequestHandler
        /// </summary>
        public IPostRequestHandler RequestHandler;

        /// <summary>
        /// 获取或设置图像请求处理程序。
        /// </summary>
        public IImageRequestHandler ImageRequestHandler { get; set; }

        /// <summary>
        /// 获取或设置请求的基本URI。
        /// </summary>
        public Uri BaseUri { get; set; }


        /// <summary>
        /// 获取二维码-接口B：适用于需要的码数量极多，或仅临时使用的业务场景
        /// </summary>
        /// <param name="scene">最大32个可见字符，只支持数字，大小写英文以及部分特殊字符：!#$&'()*+,/:;=?@-._~，其它字符请自行编码为合法字符（因不支持%，中文无法使用 urlencode 处理，请使用其他编码方式）</param>
        /// <param name="page">必须是已经发布的小程序页面，例如 "pages/index/index" ,如果不填写这个字段，默认跳主页面</param>
        /// <param name="width">二维码的宽度</param>
        /// <param name="auto_color">自动配置线条颜色，如果颜色依然是黑色，则说明不建议配置主色调</param>
        /// <param name="line_color">auto_color 为 false 时生效，使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"}</param>
        /// <returns></returns>
        public Task<byte[]> GetWxaCodeUnlimitAsync(string scene, string page, int width, bool auto_color, Color line_color)
        {
            Contract.Requires(scene != null, "scene cannot be null.");
            Contract.Requires(page != null, "page cannot be null.");
            WxAccessTokenResponse response = WxCommonApi.Instance().GetAccessToken(options.AppId, options.AppSecret);
            var relUri = "/wxa/getwxacodeunlimit?access_token=" + response.access_token;
            WxCodeUnlimitOptions  codeUnlimitOptions = new WxCodeUnlimitOptions();
            codeUnlimitOptions.scene = scene;
            codeUnlimitOptions.page = page;
            codeUnlimitOptions.width = width;
            codeUnlimitOptions.auto_color = auto_color;
            codeUnlimitOptions.line_color = new LineColor(line_color.R, line_color.G, line_color.B);
            string jsonStr = RequestHandler.Serializer.Serialize(codeUnlimitOptions);
            return ImageRequestHandler.PostRequestImageDataAsync(new Uri(BaseUri, relUri), jsonStr);
        }

        /// <summary>
        /// 获取二维码-接口B：适用于需要的码数量极多，或仅临时使用的业务场景
        /// </summary>
        /// <param name="scene">最大32个可见字符，只支持数字，大小写英文以及部分特殊字符：!#$&'()*+,/:;=?@-._~，其它字符请自行编码为合法字符（因不支持%，中文无法使用 urlencode 处理，请使用其他编码方式）</param>
        /// <param name="page">必须是已经发布的小程序页面，例如 "pages/index/index" ,如果不填写这个字段，默认跳主页面</param>
        /// <param name="width">二维码的宽度</param>
        /// <param name="auto_color">自动配置线条颜色，如果颜色依然是黑色，则说明不建议配置主色调</param>
        /// <param name="line_color">auto_color 为 false 时生效，使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"}</param>
        /// <returns></returns>
        public byte[] GetWxaCodeUnlimit(string scene, string page, int width, bool auto_color, Color line_color)
        {
            return GetWxaCodeUnlimitAsync(scene, page, width, auto_color, line_color).Result;
        }

        /// <summary>
        /// 获取二维码-接口A: 适用于需要的码数量较少的业务场景
        /// </summary>
        /// <param name="path">不能为空，最大长度 128 字节</param>
        /// <param name="width">二维码的宽度</param>
        /// <param name="auto_color">自动配置线条颜色，如果颜色依然是黑色，则说明不建议配置主色调</param>
        /// <param name="line_color">auth_color 为 false 时生效，使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"}</param>
        /// <returns></returns>
        public Task<byte[]> GetWxaCodeAsync(string path, int width, bool auto_color, Color line_color)
        {
            Contract.Requires(path != null, "path cannot be null."); ;
            WxAccessTokenResponse response = WxCommonApi.Instance().GetAccessToken(options.AppId, options.AppSecret);
            var relUri = "/wxa/getwxacode?access_token=" + response.access_token;
            WxaCodeOptions  codeOptions = new WxaCodeOptions();
            codeOptions.path = path;
            codeOptions.auto_color = auto_color;
            codeOptions.auto_color = auto_color;
            codeOptions.line_color = new LineColor(line_color.R, line_color.G, line_color.B);
            string jsonStr = RequestHandler.Serializer.Serialize(codeOptions);
            return ImageRequestHandler.PostRequestImageDataAsync(new Uri(BaseUri, relUri), jsonStr);
        }

        /// <summary>
        /// 获取二维码-接口A: 适用于需要的码数量较少的业务场景
        /// </summary>
        /// <param name="path">不能为空，最大长度 128 字节</param>
        /// <param name="width">二维码的宽度</param>
        /// <param name="auto_color">自动配置线条颜色，如果颜色依然是黑色，则说明不建议配置主色调</param>
        /// <param name="line_color">auth_color 为 false 时生效，使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"}</param>
        /// <returns></returns>
        public byte[] GetWxaCode(string path, int width, bool auto_color, Color line_color)
        {
            return GetWxaCodeAsync(path, width, auto_color, line_color).Result;
        }

        /// <summary>
        /// 获取二维码-接口C：适用于需要的码数量较少的业务场景
        /// </summary>
        /// <param name="path">不能为空，最大长度 128 字节</param>
        /// <param name="width">二维码的宽度</param>
        /// <returns></returns>
        public Task<byte[]> CreateWxaQRCodeAsync(string path, int width)
        {
            Contract.Requires(path != null, "path cannot be null."); ;
            WxAccessTokenResponse response = WxCommonApi.Instance().GetAccessToken(options.AppId, options.AppSecret);
            var uriString = "https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=" + response.access_token;
            string jsonStr = RequestHandler.Serializer.Serialize(new { path = path, width = width });
            return ImageRequestHandler.PostRequestImageDataAsync(new Uri(uriString), jsonStr);
        }

        /// <summary>
        /// 获取二维码-接口C：适用于需要的码数量较少的业务场景
        /// </summary>
        /// <param name="path">不能为空，最大长度 128 字节</param>
        /// <param name="width">二维码的宽度</param>
        /// <returns></returns>
        public byte[] CreateWxaQRCode(string path, int width)
        {
            return CreateWxaQRCodeAsync(path, width).Result;
        }

    }
}
